package com.spring.pick2pick.common;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

import org.apache.log4j.Logger;

public class DBHandler {

	static Logger logger = Logger.getLogger(DBHandler.class);
	
	private static DBHandler current = null;

	/** 접속에 필요한 객체 */
	private static Connection con = null;

	/** 접속 여부 체크 값 */
	private static boolean isConnect = false;
	
	public static DBHandler getInstance() {
		if (current == null) {
			current = new DBHandler();
		}
		return current;
	}
	
	public Connection getConnection() throws Exception {
		Context initCtx = new InitialContext();
		Context envCtx = (Context)initCtx.lookup("java:comp/env");
		DataSource ds = (DataSource)envCtx.lookup("jdbc/mydb");
		return ds.getConnection();
	}

	public boolean connect() {
		logger.debug("=========== method start >> connect");

		// 중복 접속 방지
		if (isConnect) {
			return isConnect;
		}

		try {
			con = getConnection();
			isConnect = true;
		} catch (Exception e) {
			logger.error("에러 >> 데이터 베이스 접속실패");
			logger.error(e.getLocalizedMessage());
			logger.error(e.getStackTrace());
		}

		logger.debug("=========== method end >> connect");
		return isConnect;
	}
	
	/**
	 * PreparedStatement 객체를 생성한다.
	 */
	public PreparedStatement getPrepareStatement(String sql) {
		logger.debug("=========== method start >> getPrepareStatement");
		logger.debug("[SQL] " + sql);
		
		PreparedStatement pstmt = null;
		
		try {
			if (isConnect) {
				pstmt = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
			}
		} catch (SQLException e) {
			logger.error("에러 >> SQL문 오류");
			logger.error(e.getLocalizedMessage());
			logger.error(e.getStackTrace());
		} catch (Exception e) {
			logger.error("에러 >> 알 수 없는 에러 발생함");
			logger.error(e.getLocalizedMessage());
			logger.error(e.getStackTrace());
		}
		logger.debug("=========== method end >> getPrepareStatement");
		return pstmt;
	}

	/**
	 * 접속을 해제한다.
	 */
	public void disconnect() {
		logger.debug("=========== method start >> disconnect");

		if (isConnect) {
			try {
				con.close();
				con = null;
			} catch (Exception e) {

				logger.error(e.getLocalizedMessage());
				logger.error(e.getStackTrace());
			}

			// 상태변경
			isConnect = false;
		}
		logger.debug("=========== method end >> disconnect");
	}

	/**
	 * 트렌젝션을 시작한다.
	 */
	public void beginTrans() {
		logger.debug("=========== method start >> beginTrans");

		try {
			con.setAutoCommit(false);
		} catch (SQLException e) {
			logger.error("트렌젝션 시작 실패 >> " + e.getLocalizedMessage());
			logger.error(e.getLocalizedMessage());
			logger.error(e.getStackTrace());
		}
		logger.debug("=========== method end >> beginTrans");
	}

	/**
	 * 트렌젝션을 종료하고 커밋한다.
	 */
	public void commit() {
		logger.debug("=========== method start >> commit");

		try {
			con.commit();
		} catch (SQLException e) {
			logger.error("커밋 실패 >> " + e.getLocalizedMessage());
			logger.error(e.getLocalizedMessage());
			logger.error(e.getStackTrace());
		}

		logger.debug("=========== method end >> commit");
	}

	/**
	 * 트렌젝션을 종료하고 롤백한다.
	 */
	public void rollback() {
		logger.debug("=========== method start >> rollback");

		try {
			con.rollback();
		} catch (SQLException e) {
			logger.error("롤백 실패 >> " + e.getLocalizedMessage());

			logger.error(e.getLocalizedMessage());
			logger.error(e.getStackTrace());
		}

		logger.debug("=========== method end >> rollback");
	}
	
	/**
	 * DB에게 COUNT함수를 사용한 질의 결과를 받아 리턴한다.
	 * 
	 * @param table
	 *            테이블 이름
	 * @param column
	 *            COUNT함수를 적용할 컬럼 이름
	 * @param where
	 *            WHERE절 (필요한 경우 사용)
	 * @return 조건에 맞는 데이터의 수
	 */
	public int getCount(String table, String column, String where) {
		logger.debug("=========== method start >> getCount");
		
		int result = 0;

		String sql = "SELECT COUNT(" + column + ") FROM " + table;
		
		if (where != null) {
			sql = sql + " WHERE " + where;
		}

		PreparedStatement pstmt = getPrepareStatement(sql);
		try {
			ResultSet rs = pstmt.executeQuery();
			if (rs != null) {
				if (rs.next()) {
					result = rs.getInt(1);
				}
				rs.close();
				rs = null;
			}
			pstmt.close();
			pstmt = null;
		} catch (SQLException e) {
			logger.error(e.getLocalizedMessage());
			logger.error(e.getSQLState());
			logger.error(e.getStackTrace());
		}
		
		logger.debug("=========== method end >> getCount");
		return result;
	}

	/**
	 * DB에게 MAX함수를 사용한 질의 결과를 받아 리턴한다.
	 * 
	 * @param table
	 *            테이블 이름
	 * @param column
	 *            COUNT함수를 적용할 컬럼 이름
	 * @param where
	 *            WHERE절 (필요한 경우 사용)
	 * @return 조건에 맞는 데이터의 수
	 */
	public int getMax(String table, String column, String where) {
		logger.debug("=========== method start >> getMax");

		int result = 0;

		String sql = "SELECT MAX(" + column + ") FROM " + table;

		if (where != null) {
			sql = sql + " WHERE " + where;
		}

		PreparedStatement pstmt = getPrepareStatement(sql);
		
		try {
			ResultSet rs = pstmt.executeQuery();
			if (rs != null) {
				if (rs.next()) {
					result = rs.getInt(1);
				}
				rs.close();
				rs = null;
			}
			pstmt.close();
			pstmt = null;
		} catch (SQLException e) {
			logger.error(e.getLocalizedMessage());
			logger.error(e.getSQLState());
			logger.error(e.getStackTrace());
		}

		logger.debug("=========== method end >> getMax");
		return result;
	}

	/**
	 * DB에게 MIN함수를 사용한 질의 결과를 받아 리턴한다.
	 * 
	 * @param table
	 *            테이블 이름
	 * @param column
	 *            COUNT함수를 적용할 컬럼 이름
	 * @param where
	 *            WHERE절 (필요한 경우 사용)
	 * @return 조건에 맞는 데이터의 수
	 */
	public int getMin(String table, String column, String where) {
		logger.debug("=========== method start >> getMin");

		int result = 0;

		String sql = "SELECT MIN(" + column + ") FROM " + table;

		if (where != null) {
			sql = sql + " WHERE " + where;
		}

		PreparedStatement pstmt = getPrepareStatement(sql);
		
		try {
			ResultSet rs = pstmt.executeQuery();
			if (rs != null) {
				if (rs.next()) {
					result = rs.getInt(1);
				}
				rs.close();
				rs = null;
			}
			pstmt.close();
			pstmt = null;
		} catch (SQLException e) {
			logger.error(e.getLocalizedMessage());
			logger.error(e.getSQLState());
			logger.error(e.getStackTrace());
		}

		logger.debug("=========== method end >> getMin");
		return result;
	}
	
	public int getSum(String table, String column, String where) {
		logger.debug("=========== method start >> getSum");

		int result = 0;

		String sql = "SELECT SUM(" + column + ") FROM " + table;

		if (where != null) {
			sql = sql + " WHERE " + where;
		}

		PreparedStatement pstmt = getPrepareStatement(sql);
		
		try {
			ResultSet rs = pstmt.executeQuery();
			if (rs != null) {
				if (rs.next()) {
					result = rs.getInt(1);
				}
				rs.close();
				rs = null;
			}
			pstmt.close();
			pstmt = null;
		} catch (SQLException e) {
			logger.error(e.getLocalizedMessage());
			logger.error(e.getSQLState());
			logger.error(e.getStackTrace());
		}

		logger.debug("=========== method end >> getSum");
		return result;
	}
	
}
